/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.osiris.persistence;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import javax.annotation.Resource;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.apache.log4j.Logger;
import org.osiris.client.model.ProyectoViewBean;
import org.osiris.client.model.UsuarioViewBean;
import org.osiris.persistence.controllers.IncertidumbreInterface;
import org.osiris.persistence.controllers.PrioridadInterface;
import org.osiris.persistence.controllers.ProyectoInterface;
import org.osiris.persistence.controllers.RequisitoDeProyectoInterface;
import org.osiris.persistence.controllers.RequisitoInterface;
import org.osiris.persistence.controllers.UsuarioInterface;
import org.osiris.persistence.controllers.exceptions.NonexistentEntityException;
import org.osiris.persistence.controllers.impl.RequisitosdeproyectoJpaController;
import org.osiris.server.engine.EmailNotificacion;
import org.osiris.server.engine.Notificador;
import org.osiris.server.utils.AppContext;
import org.springframework.context.ApplicationContext;

/**
 *
 * @author amartinez
 */

@Entity
@Table(name = "Proyecto")
@NamedQueries({@NamedQuery(name = "Proyecto.findAll", query = "SELECT p FROM Proyecto p"), @NamedQuery(name = "Proyecto.findByIdProyecto", query = "SELECT p FROM Proyecto p WHERE p.idProyecto = :idProyecto"), @NamedQuery(name = "Proyecto.findByNombre", query = "SELECT p FROM Proyecto p WHERE p.nombre = :nombre"), @NamedQuery(name = "Proyecto.findByCliente", query = "SELECT p FROM Proyecto p WHERE p.cliente = :cliente"), @NamedQuery(name = "Proyecto.findByEstado", query = "SELECT p FROM Proyecto p WHERE p.estado = :estado"), @NamedQuery(name = "Proyecto.findByFechaalta", query = "SELECT p FROM Proyecto p WHERE p.fechaalta = :fechaalta"), @NamedQuery(name = "Proyecto.findByReferencia", query = "SELECT p FROM Proyecto p WHERE p.referencia = :referencia"), @NamedQuery(name = "Proyecto.findByDescripcion", query = "SELECT p FROM Proyecto p WHERE p.descripcion = :descripcion")})
public class Proyecto extends Observable implements Serializable,Observer {
    
    
	@Transient
	@Resource
	RequisitosdeproyectoJpaController RequisitosdeproyectoJpaController;
    private static final long serialVersionUID = 1L;
    @Transient
	private Logger logger = Logger.getLogger(this.getClass());
    @Transient
    ApplicationContext ctx = AppContext.getApplicationContext();
    @Transient
    @Resource
    ProyectoInterface proyectoDAO = null;
    @Transient
    @Resource
	private IncertidumbreInterface incertidumbreDAO;
    @Transient
	@Resource
	private PrioridadInterface prioridadDAO;
    @Transient
    @Resource
    private UsuarioInterface usuarioDAO;
    @Transient
    @Resource
	private RequisitoInterface requisitoDAO;
    public void anadirInteresado(Usuario user){
		this.addObserver(user);
	}
    
    public void quitarInteresado(Usuario user){
		this.deleteObserver(user);
	}
	

	public boolean guardar() {
		
		
		
		try {
			proyectoDAO.create(this);
			logger.error("Creado on ID:"+this.getIdProyecto());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error("Pero no se ha creado");
			e.printStackTrace();
		}
		return true;
	}

	
	public boolean desasociarRequisito(Requisito requisito) {
		
		// mientras el requisito no sea el contenido en lista de requisitos y no se salga del la longitud de la lista....
		 int i=0;
		 while (!requisito.equals(requisitosdeproyectoList.get(i).getRequisito()) && i<requisitosdeproyectoList.size() )
		{
			 i++;
		}
		requisitosdeproyectoList.remove(i);
		this.notifyObservers("RequisitoDesasociado");
		requisito.quitarProyectoObservador(this);
		this.quitarInteresado(requisito.getResponsable());
		return true;
	}

	public boolean desasociarRequisito(Long requisito) {
		
		
		if(RequisitosdeproyectoJpaController==null){
			RequisitosdeproyectoJpaController=(RequisitosdeproyectoJpaController) ctx.getBean("RequisitosdeproyectoJpaController");
		}
		Requisitosdeproyecto rel = RequisitosdeproyectoJpaController.buscarPorRequisito(requisito, this.getIdProyecto());
		logger.info("Tratando de desasociar el requisito:"+requisito +" del proyecto "+this.getIdProyecto());
		try {
			RequisitosdeproyectoJpaController.destroy(rel.getRequisitosdeproyectoPK());
		} catch (NonexistentEntityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return true;
	}
	public boolean asociarRequisito(long idRequisito,long prioridad, long incertidumbre,String situacion,long usuarioAlta) {
		iniciar();
		Requisitosdeproyecto reqpro=new Requisitosdeproyecto();
		logger.info("Creando dependecia con requisito para el proyecto:"+this.getIdProyecto());
		logger.info("crearRequisitoDeProyecto para requisito2:"+idRequisito+" prioridad:"+
				prioridad+" incertidumbre:"+incertidumbre+" situacion:"+situacion+" proyecto:"+this
				+" usuario:"+usuarioAlta);
		reqpro.setEstadoRequistoEnProyecto(situacion);
		setFechaalta(new Date());
		Incertidumbre in = incertidumbreDAO.findIncertidumbre(incertidumbre);
		reqpro.setIdIncertidumbre(in);
		reqpro.setIdPrioridadRequisito(this.prioridadDAO.findPrioridadrequisito(prioridad));
		
		Usuario u = usuarioDAO.findUsuario(usuarioAlta);
		reqpro.setUsuario(u);
		logger.info("proyecto.getIdProyecto():"+this.getIdProyecto());
		RequisitosdeproyectoPK requisitosdeproyectoPK=new RequisitosdeproyectoPK();
		requisitosdeproyectoPK.setIdProyecto(this.getIdProyecto());
		Requisito requisito=this.requisitoDAO.findRequisito(idRequisito);
		requisitosdeproyectoPK.setIdRequisito(requisito.getIdRequisito());
		requisitosdeproyectoPK.setUsuarioalta(u.getIdUsuario());    
		reqpro.setRequisitosdeproyectoPK(requisitosdeproyectoPK);
		reqpro.setRequisito(requisito);
		reqpro.setProyecto(this);
		reqpro.guardar();

		requisito.anadirProyectoObservador(this);
		this.anadirInteresado(requisito.getResponsable());
		this.notifyObservers("RequisitoAsociado");
		return true;
	}

	public boolean altaDeCambio(Peticioncambio pet) {
		return false;
	}

	public boolean evaluarCambio(Peticioncambio pet, Double esfuerzo) {
		return false;
	}

	public boolean aceptarCambio(Peticioncambio pet) {
		return false;
	}

	public boolean rechazarCambio(Peticioncambio pet) {
		return false;
	}

	public ProyectoViewBean toView() {
		try {
			Proyecto p = this;
			logger.info("Created:" + p);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		ProyectoViewBean pr = new ProyectoViewBean();
		pr.setcliente(this.getCliente());
		pr.setdescripcion(this.getDescripcion());
		pr.setestado(this.getEstado().toString());
		pr.setfechaalta(this.getFechaalta());
		pr.setidProyecto(this.getIdProyecto());
		
		
		pr.setnumreq((((int)(Math.random()*10))));
		pr.setcomplejidadglobal((((int)(Math.random()*10))));
		pr.setexposicion((((int)(Math.random()*10))));
		pr.setconflictos((((int)(Math.random()*10))));
		pr.setincertidumbreglobal((((int)(Math.random()*10))));
		pr.setpetcambpend((((int)(Math.random()*10))));
		pr.setpetcambioreject((((int)(Math.random()*10))));
		pr.setpeticionescambioaccep((((int)(Math.random()*10))));
		
		pr.setnombre(this.getNombre());
		pr.setreferencia(this.getReferencia());
		try {
			pr.setautor(new UsuarioViewBean(this.getUsuarioidUsuario().getIdUsuario(),this.getUsuarioidUsuario().getNombre()+" " +this.getUsuarioidUsuario().getPrimerApellido()));
		} catch (Exception me) {
		}
		try {
			pr.setresponsable(new UsuarioViewBean(this.getUsuarioidUsuario().getIdUsuario(),this.getUsuarioidUsuario().getNombre()+" " +this.getUsuarioidUsuario().getPrimerApellido()));
		} catch (Exception me) {
		}
		pr.setresumen(this.getResumen());
		pr.setfechainicio(this.getFechainicio());

		return pr;
	}
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)    
    @Column(name = "idProyecto")
    private Long idProyecto;
    @Column(name = "Nombre")
    private String nombre;
    @Column(name = "Cliente")
    private String cliente;
    @Column(name = "Estado")
    private String estado;
    
    @Column(name = "Fecha_inicio")
    @Temporal(TemporalType.TIMESTAMP)
    private Date fechainicio;
    
    @Column(name = "Fecha_baja")
    @Temporal(TemporalType.TIMESTAMP)
    private Date fechabaja;
    @Column(name = "Fecha_alta")
    @Temporal(TemporalType.TIMESTAMP)
    private Date fechaalta;
    @Column(name = "Resumen")
    private String resumen;
    @Column(name = "Referencia")
    private String referencia;
    @Column(name = "Descripcion")
    private String descripcion;
    @JoinColumn(name = "Usuario_idUsuario", referencedColumnName = "idUsuario")
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Usuario usuarioidUsuario;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "proyecto", fetch = FetchType.LAZY)
    private List<Requisitosdeproyecto> requisitosdeproyectoList;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "proyecto", fetch = FetchType.LAZY)
    private List<Asignacionesproyecto> asignacionesproyectoList;

    public Proyecto() {
    	//this.requisitosdeproyectoList=new Vector<Requisitosdeproyecto> ();
    }

    public Proyecto(Long idProyecto) {
        this.idProyecto = idProyecto;
    }

    public Long getIdProyecto() {
        return idProyecto;
    }

    public void setIdProyecto(Long idProyecto) {
        this.idProyecto = idProyecto;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public String getCliente() {
        return cliente;
    }

    public void setCliente(String cliente) {
        this.cliente = cliente;
    }

    public String getEstado() {
        return estado;
    }

    public void setEstado(String estado) {
        this.estado = estado;
    }

    public Date getFechaalta() {
        return fechaalta;
    }

    public void setFechaalta(Date fechaalta) {
        this.fechaalta = fechaalta;
    }

    public String getReferencia() {
        return referencia;
    }

    public void setReferencia(String referencia) {
        this.referencia = referencia;
    }

    public String getDescripcion() {
        return descripcion;
    }

    public void setDescripcion(String descripcion) {
        this.descripcion = descripcion;
    }

    public Usuario getUsuarioidUsuario() {
        return usuarioidUsuario;
    }

    public void setUsuarioidUsuario(Usuario usuarioidUsuario) {
        this.usuarioidUsuario = usuarioidUsuario;
    }

    public List<Requisitosdeproyecto> getRequisitosdeproyectoList() {
        return requisitosdeproyectoList;
    }

    public void setRequisitosdeproyectoList(List<Requisitosdeproyecto> requisitosdeproyectoList) {
        this.requisitosdeproyectoList = requisitosdeproyectoList;
    }

    public List<Asignacionesproyecto> getAsignacionesproyectoList() {
        return asignacionesproyectoList;
    }

    public void setAsignacionesproyectoList(List<Asignacionesproyecto> asignacionesproyectoList) {
        this.asignacionesproyectoList = asignacionesproyectoList;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (idProyecto != null ? idProyecto.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Proyecto)) {
            return false;
        }
        Proyecto other = (Proyecto) object;
        if ((this.idProyecto == null && other.idProyecto != null) || (this.idProyecto != null && !this.idProyecto.equals(other.idProyecto))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.osiris.persistence.Proyecto[idProyecto=" + idProyecto + "]";
    }

	public Date getFechabaja() {
		return fechabaja;
	}

	public void setFechabaja(Date fechabaja) {
		this.fechabaja = fechabaja;
	}

	public Date getFechainicio() {
		return fechainicio;
	}

	public void setFechainicio(Date fechainicio) {
		this.fechainicio = fechainicio;
	}

	public String getResumen() {
		return resumen;
	}

	public void setResumen(String resumen) {
		this.resumen = resumen;
	}
	
	public void update(Observable o, Object arg) {
		boolean mensajeInteresante=false;
		String asunto="Asunto sin identificar";
		String cuerpoPlano="Sin mensaje";
		
		if(arg.toString().equals("NuevaDependencia")){
			asunto="Dependencia creada entre requisitos";
			cuerpoPlano="Se notifica al usuario: "+this.getUsuarioidUsuario().getNombre()+" que el requisito "+((Requisito)o).getNombre()+", con identificador: "+((Requisito)o).getIdRequisito()+"ha sido asociado a otro requisito.";
			mensajeInteresante=true;
		}
		if(arg.toString().equals("NuevoRiesgo")){
			asunto="Nuevo de riesgo de un requisito";
			cuerpoPlano="Se notifica al usuario: "+this.getUsuarioidUsuario().getNombre()+" que el requisito "+((Requisito)o).getNombre()+", con identificador: "+((Requisito)o).getIdRequisito()+"ha creado un riesgo nuevo.";
			mensajeInteresante=true;
		}
		if(arg.toString().equals("RiesgoEliminado")){
			asunto="Eliminacion de riesgo de un requisito";
			cuerpoPlano="Se notifica al usuario: "+this.getUsuarioidUsuario().getNombre()+" que el requisito "+((Requisito)o).getNombre()+", con identificador: "+((Requisito)o).getIdRequisito()+"ha eliminado uno de sus riesgos.";
			mensajeInteresante=true;
		}
		if(arg.toString().equals("Modificacion")){
			asunto="Modificacion de un requisito";
			cuerpoPlano="Se notifica al usuario: "+this.getUsuarioidUsuario().getNombre()+" que el requisito "+((Requisito)o).getNombre()+", con identificador: "+((Requisito)o).getIdRequisito()+"ha sido modificado.";
			mensajeInteresante=true;
		}
		
		if(arg.toString().equals("Rechazo")){
			asunto="Requisito Reqchazado";
			cuerpoPlano="Se notifica al usuario: "+this.getUsuarioidUsuario().getNombre()+" que el requisito "+((Requisito)o).getNombre()+", con identificador: "+((Requisito)o).getIdRequisito()+"ha sido" +
			"rechazado y que ya no emitira ningun otro mensaje hasta que no cambie de estado.";
			mensajeInteresante=true;
			// si el requisito se rechaza el proyecto lo desasocia automaticamente
			this.desasociarRequisito((Requisito)o);
		}
		
		
		
		
		
		if(mensajeInteresante){
			Notificador.colaNotificaciones.add(new EmailNotificacion(this.getUsuarioidUsuario().getEmail(), asunto, cuerpoPlano,this.getUsuarioidUsuario().getEmail()));
		}
			
	}
	public void iniciar(){
    	if(incertidumbreDAO==null){
    		incertidumbreDAO=(IncertidumbreInterface) ctx.getBean("IncertidumbreJpaController");
		}
    	if(requisitoDAO==null){
    		requisitoDAO=(RequisitoInterface) ctx.getBean("RequisitoJpaController");
		}
    	
    	if(prioridadDAO==null){
    		prioridadDAO=(PrioridadInterface) ctx.getBean("PrioridadrequisitoJpaController");
		}
    	
    	if(usuarioDAO==null){
    		usuarioDAO=(UsuarioInterface) ctx.getBean("UsuarioJpaController");
		}
    	if(proyectoDAO==null){
			proyectoDAO=(ProyectoInterface) ctx.getBean("ProyectoJpaController");
		}
    }
	public void cerrar() {
		this.setEstado("Cerrado");
		this.notifyObservers("ProyectoCerrado");
		this.deleteObservers();
		
	}



}
